package cn.bluedot.tea.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import cn.bluedot.framework.dao.PoolManager;
import cn.bluedot.framework.dao.PooledConnection;
import cn.bluedot.framework.dao.PooledDataSource;
import cn.bluedot.framework.dao.View;
import cn.bluedot.framework.util.BeanUtil;
import cn.bluedot.framework.util.SqlParser;

public class BaseDao {
	//准备一个连接对象
	private static PooledDataSource pooledDataSource = PoolManager.getInstance();
	
	//执行SQL
	public static int excute(Map<String, Object> params) throws Exception {
		//通过传入的name在view.xml中得到View对象，根据View中的method查找对应的解析SQL
		String name = (String) params.get("view"); //获取view的名称
		View view = SqlParser.getView(name); //得到View对象
		
		if(view == null) {
			throw new Exception("xml中不存在："+name+"对应的view");
		}
		
		String method = view.getMethod(); //得到View对象的method属性值
		params.remove("view");
		if(View.METHOD_INSERT.equals(method)) {
			List<Object> param = new ArrayList<Object>();
			String sql = SqlParser.insert(view, params, param);
			return insert(sql, param);
		} else if(View.METHOD_DELETE.equals(method)) {
			List<Object> param = new ArrayList<Object>();
			String sql = SqlParser.delete(view, params, param);
			return delete(sql, param);
		} else if(View.METHOD_UPDATE.equals(method)) {
			List<Object> param = new ArrayList<Object>();
			String sql = SqlParser.update(view, params, param);
			return update(sql, param);
		} else if(View.METHOD_SELECT.equals(method)) {
			System.out.println("请使用excuteQuery完成查询操作...");
		} else {
			throw new Exception("View method not found.");
		}
		return 0;
	}
	
	/**
	 * 查询
	 * @param params 查询参数值
	 * @param cls Class对象
	 * @return Class对象不为空时用于查询单个对象映射结果，返回Class对象
	 * @throws Exception
	 */
	public static <T> Object excuteQuery(Map<String, Object> params, Class<T> cls) throws Exception {
		
		//通过传入的name在view.xml中得到View对象，根据View中的method查找对应的解析SQL
		String name = (String) params.get("view"); //获取view的名称
		View view = SqlParser.getView(name); //得到View对象
		
		if(view == null) {
			throw new Exception("xml中不存在："+name+"对应的view");
		}
		
		params.remove("view");
		List<Object> param = new ArrayList<Object>();
		String sql = SqlParser.select(view, params, param);
		
		Object select = select(sql, param, cls);
		
		return select;
	}
	
	/**
	 * 查询
	 * @param sql
	 * @param params
	 * @param cls
	 * @return
	 * @throws Exception
	 */
	private static <T> Object  select(String sql, List<Object> params, Class<T> cls) throws Exception{
		//连接数据库
		PooledConnection pooledConnection = pooledDataSource.getConnection();
		Connection connection = pooledConnection.getConn();
	
		PreparedStatement pstmt = null;
		ResultSet result = null;
		
		try {
			pstmt = connection.prepareStatement(sql);
			initParams(pstmt, params); //初始化对应的参数
			result = pstmt.executeQuery(); //执行查询			
			return getResultReturn(cls, result);
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if(result != null)
				result.close();
			if(pstmt != null)
				pstmt.close();
			pooledConnection.close();
		}
		
		return null;
	}

	/**
	 * 得到结果集返回值
	 * @param cls
	 * @param result
	 * @return
	 * @throws SQLException
	 * @throws Exception
	 */
	private static <T> Object getResultReturn(Class<T> cls, ResultSet result) throws Exception {
		/**
		 * 1.判断结果集大小
		 * 2.如果结果集大小为1，则判断Class<T>是否为空
		 * 3.如果Class<T>为空则可判断为count查询,否则将结果集转为对象
		 * 4.如果结果集大小大于1，则将结果集转为List
		 */
		int size = getResultSetSize(result);
		
		if(size == 0) {
			return null;
		}
		
		if(size == 1 && cls == null) {//返回个数
			if(result.next()) {
				Object object = result.getObject(1);
				if(object instanceof Long) {
					return Integer.parseInt(String.valueOf(object));
				} else {
					return object;
				}
			}
		}
		
		List<Map<String, Object>> list = BeanUtil.getListHashMap(result);
		if(size == 1 && cls != null) {
			return BeanUtil.toBean(list.get(0), cls); //返回对象
		} 
		
		if(size > 1 && cls != null){
			return BeanUtil.toBeanList(list, cls); //返回对象List
		}
		
		return list;
	}
	
	
	/**
	 * 添加
	 * @param sql
	 * @param params
	 * @return
	 */
	private static int insert(String sql, List<Object> params) {
		PooledConnection pooledConnection = pooledDataSource.getConnection();
		Connection connection = pooledConnection.getConn();
		PreparedStatement pstmt = null;
		
		try {
			pstmt = connection.prepareStatement(sql);
			initParams(pstmt, params);
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(pstmt != null)
					pstmt.close();
				pooledConnection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return 0;
	}
	
	/**
	 * 删除
	 * @param sql
	 * @param params
	 * @return
	 * @throws SQLException
	 */
	private static int delete(String sql, List<Object> params) throws SQLException {
		PooledConnection pooledConnection = pooledDataSource.getConnection();
		Connection connection = pooledConnection.getConn();
		PreparedStatement pstmt = null;
		
		try {
			pstmt = connection.prepareStatement(sql);
			initParams(pstmt, params);
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if(pstmt != null)
				pstmt.close();
			pooledConnection.close();
		}
		
		return 0;
	}
	
	/**
	 * 更新
	 * @param sql
	 * @param params
	 * @return
	 * @throws SQLException
	 */
	private static int update(String sql, List<Object> params) throws SQLException {
		PooledConnection pooledConnection = pooledDataSource.getConnection();
		Connection connection = pooledConnection.getConn();
		PreparedStatement pstmt = null;
		try {
			pstmt = connection.prepareStatement(sql);
			initParams(pstmt, params);
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if(pstmt != null)
				pstmt.close();
			pooledConnection.close();
		}
		return 0;
	}
	
	
	/**
	 * 初始化传入参数，将传入参数注入到PreparedStatement中
	 * @param pst
	 * @param params
	 * @throws SQLException
	 */
	private static void initParams(PreparedStatement pst, List<Object> params) throws SQLException {
		for (int i = 0; i < params.size(); i++) {
			pst.setObject(i + 1, params.get(i));
		}
	}
	
	/**
	 * 得到结果集的大小
	 * @param rs
	 * @return
	 * @throws SQLException
	 */
	private static int getResultSetSize(ResultSet rs) throws SQLException {
		rs.last();// 移动到最后
		int size = rs.getRow();// 获得结果集长度
		rs.beforeFirst();
		return size;
	}
}